﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Djs.Neuronic.Core;

namespace Djs.Neuronic.Medium
{
    #region DialogSetInfo : Sada dialogových oken.
    /// <summary>
    /// DialogSetInfo : Sada dialogových oken.
    /// </summary>
    public class DialogSetInfo
    {
        #region Konstrukce
        public DialogSetInfo()
        {
            this._PageList = new List<DialogPageInfo>();
            this._PageDict = new Dictionary<string, DialogPageInfo>();
            this._MainPage = null;
            this._EndPage = null;
            this._Background = DialogBackground.DefaultFlat;
            this._Background.BackBrushGenerator = this.DialogBackgroundGenerator;
            this._LabelFont = new Font(SystemFonts.MenuFont.Name, 12f, FontStyle.Bold);
        }
        private List<DialogPageInfo> _PageList;
        private Dictionary<string, DialogPageInfo> _PageDict;
        private DialogPageInfo _MainPage;
        private DialogPageInfo _EndPage;
        private DialogBackground _Background;
        private Font _LabelFont;
        private Brush DialogBackgroundGenerator(Rectangle bound)
        {
            System.Drawing.Drawing2D.LinearGradientBrush lgb = new System.Drawing.Drawing2D.LinearGradientBrush(bound, Color.DarkBlue, Color.LightBlue, 90f);
            return lgb;
        }
        #endregion
        #region Public property a metody
        /// <summary>
        /// Vstupní stránka dialogu
        /// </summary>
        public DialogPageInfo MainPage { get { return this._MainPage; } set { this._MainPage = value; } }
        /// <summary>
        /// Koncová stránka dialogu, na kterou se přechází akcí DialogActionType.GoToEndPage.
        /// Typicky je to stránka, která má timeout, jehož akcí je DialogActionType.ApplicationExitNoQuerry (konec aplikace bez dotazu).
        /// Pokud dialog nemá definovanou koncovou stránku, pak akce GoToEndPage se chová jako ApplicationExit (konec aplikace s dotazem).
        /// </summary>
        public DialogPageInfo EndPage { get { return this._EndPage; } set { this._EndPage = value; } }
        /// <summary>
        /// Společné písmo labelů. Použije se tehdy, když label nemá definovaný svůj font.
        /// Implicitní písmo (pokud nebude zadáno jinak) je 
        /// </summary>
        public Font LabelFont { get { return this._LabelFont; } set { this._LabelFont = value; } }
        /// <summary>
        /// Pozadí dialogu výchozí
        /// </summary>
        public DialogBackground Background { get { return this._Background; } set { this._Background = value; } }
        /// <summary>
        /// Vloží stránku dialogu.
        /// Stránka může mít klíč (Key), pak se na ni ostatní stránky mohou odkazovat (ze své konkrétní akce) tímto klíčem.
        /// </summary>
        /// <param name="page"></param>
        public void Add(DialogPageInfo page)
        {
            this.Add(page, page.PageType);
        }
        /// <summary>
        /// Vloží stránku dialogu.
        /// Stránka může mít klíč (Key), pak se na ni ostatní stránky mohou odkazovat (ze své konkrétní akce) tímto klíčem.
        /// </summary>
        /// <param name="page"></param>
        public void Add(DialogPageInfo page, DialogPageType pageType)
        {
            page.Owner = this;
            this._PageList.Add(page);
            if (!String.IsNullOrEmpty(page.Key))
                this._PageDict.Add(page.Key, page);
            if (this._MainPage == null || pageType == DialogPageType.Main)
                this._MainPage = page;
            if (pageType == DialogPageType.End)
                this._EndPage = page;
        }
        /// <summary>
        /// Vrátí stránku, definovanou danou akcí.
        /// </summary>
        /// <param name="actionInfo"></param>
        /// <returns></returns>
        public DialogPageInfo GetPage(DialogActionInfo actionInfo)
        {
            if (actionInfo == null) return null;
            if (actionInfo.NewPage != null) return actionInfo.NewPage;
            if (!String.IsNullOrEmpty(actionInfo.NewPageKey))
            {
                DialogPageInfo page;
                if (this._PageDict.TryGetValue(actionInfo.NewPageKey, out page))
                    return page;
            }
            return null;
        }
        #endregion
    }
    #endregion
    #region DialogPageInfo : Popis jedné stránky dialogu
    /// <summary>
    /// DialogPageInfo : Popis jedné stránky dialogu
    /// </summary>
    public class DialogPageInfo
    {
        #region Konstrukce, Proměnné
        /// <summary>
        /// Výchozí konstruktor naplní akci Exit = ApplicationExit, ostatní nechá null
        /// </summary>
        public DialogPageInfo(DialogPageType pageType)
        {
            this._Key = null;
            this._PageType = pageType;
            if (pageType != DialogPageType.End)
                this.ButtonExitAction = new DialogActionInfo(DialogActionType.GoToEndPage);
            this._InputItems = new List<DialogActionInfo>();
        }
        /// <summary>
        /// Výchozí konstruktor naplní akci Exit = ApplicationExit, ostatní nechá null
        /// </summary>
        public DialogPageInfo(string key)
        {
            this._Key = key;
            this._PageType = DialogPageType.Standard;
            this.ButtonExitAction = new DialogActionInfo(DialogActionType.GoToEndPage);
            this._InputItems = new List<DialogActionInfo>();
        }
        private string _Key;
        private DialogPageType _PageType;
        private DialogBackground _Background;
        private DialogLabelInfo _Label;
        private DialogActionInfo _ButtonExitAction;
        private DialogActionInfo _ButtonPrevAction;
        private List<DialogActionInfo> _InputItems;
        private DialogActionInfo _ButtonNextAction;
        private DialogActionInfo _TimeOutAction;
        #endregion
        #region Public property
        /// <summary>
        /// Vlastník objektu
        /// </summary>
        public DialogSetInfo Owner { get; set; }
        /// <summary>
        /// Typ stránky
        /// </summary>
        public DialogPageType PageType { get { return this._PageType; } }
        /// <summary>
        /// Klíč stránky. slouží k její identifikaci
        /// </summary>
        public string Key { get { return this._Key; } }
        /// <summary>
        /// Pozadí dialogu
        /// </summary>
        public DialogBackground Background { get { return this._Background; } set { this._Background = value; if (this._Background != null) this._Background.Owner = this; } }
        /// <summary>
        /// Pozadí dialogu - zdejší nebo společné (pokud zdejší this.Background není zadáno)
        /// </summary>
        public DialogBackground CurrentBackground { get { return (this._Background != null ? this._Background : this.Owner.Background); } }
        /// <summary>
        /// Label = statická informace
        /// </summary>
        public DialogLabelInfo Label { get { return this._Label; } set { this._Label = value; if (this._Label != null) this._Label.Owner = this; } }
        /// <summary>
        /// Akce pro button Exit
        /// </summary>
        public DialogActionInfo ButtonExitAction { get { return this._ButtonExitAction; } set { this._ButtonExitAction = value; if (this._ButtonExitAction != null) this._ButtonExitAction.Owner = this; } }
        /// <summary>
        /// Akce pro button Prev (doleva, zpět)
        /// </summary>
        public DialogActionInfo ButtonPrevAction { get { return this._ButtonPrevAction; } set { this._ButtonPrevAction = value; if (this._ButtonPrevAction != null) this._ButtonPrevAction.Owner = this; } }
        /// <summary>
        /// Sada vstupních položek, nabízí se v ComboBoxu.
        /// Pokud je prázdné, vstupní pole se nezobrazuje.
        /// Pokud má mít combobox možnost volného zadávání textu, musí obsahovat jednu akci s hodnotou ActionText = null;
        /// Pokud obsahuje pouze jedinou takovou položku (ActionText = null), pak se zobrazuje jako Textbox.
        /// </summary>
        public IEnumerable<DialogActionInfo> InputItems { get { return this._InputItems; } }
        /// <summary>
        /// Akce pro button Next (doprava, vpřed)
        /// </summary>
        public DialogActionInfo ButtonNextAction { get { return this._ButtonNextAction; } set { this._ButtonNextAction = value; if (this._ButtonNextAction != null) this._ButtonNextAction.Owner = this; } }
        /// <summary>
        /// Zobrazený obrázek vpravo pod buttonem Exit, emotikon
        /// </summary>
        public Image ImagePortrait { get; set; }
        /// <summary>
        /// Čas pro automatické ukončení okna.
        /// Pokud do této doby od zobrazení okna nevybere uživatel žádnou akci, provede se akce TimeOutAction.
        /// Ubíhající čas je zobrazován pod vstupním polem, ale pouze posledních 15 sekund.
        /// Pokud je null, nebo TimeOutAction má akci None, pak se TimeOut neaktivuje.
        /// </summary>
        public double? TimeOut { get; set; }
        /// <summary>
        /// Akce provedená po uplynutí TimeOutu.
        /// </summary>
        public DialogActionInfo TimeOutAction { get { return this._TimeOutAction; } set { this._TimeOutAction = value; if (this._TimeOutAction != null) this._TimeOutAction.Owner = this; } }
        /// <summary>
        /// Stránka, ze které jsme na tuto stránku přišli akci typu CallHandler nebo GoToPage.
        /// Pokud bude na zdejší stránce zvolena akce typu GoToPrevPage, pak se na tu stránku vrátíme.
        /// Ale na tu stránku nebudeme vepisovat PrevPage = this, protože nepotřebujeme cyklit 
        /// mezi dvěma stránkami PrevPage1 -» PrevPage2 -» PrevPage1 ...
        /// </summary>
        public DialogPageInfo PrevPage { get; set; }
        #endregion
    }
    #endregion
    #region DialogBackground : Třída definující pozadí dialogu (styl, barva, atd).
    /// <summary>
    /// DialogBackground : Třída definující pozadí dialogu (styl, barva, atd).
    /// Lze ji klonovat a používat opakovaně jako styl.
    /// </summary>
    public class DialogBackground
    {
        #region Konstrukce
        /// <summary>
        /// Deklarace vlastností pozadí (barva, obrázek, generátor pozadí)
        /// </summary>
        public DialogBackground()
        {
            this.BackColor = Color.DarkBlue.Morph(Color.DarkSlateBlue, 0.1f);
        }
        /// <summary>
        /// Obsahuje defaultní pozadí, tmavě modrou barvu
        /// </summary>
        public static DialogBackground DefaultFlat
        {
            get { return new DialogBackground() { BackColor = Color.DarkBlue }; }
        }
        #endregion
        #region Public property a metody
        /// <summary>
        /// Vlastník objektu = stránka
        /// </summary>
        public DialogPageInfo Owner { get; set; }
        /// <summary>
        /// Barva pozadí
        /// </summary>
        public Color? BackColor { get; set; }
        /// <summary>
        /// Generátor štětce pro výplň pozadí
        /// </summary>
        public Func<Rectangle, Brush> BackBrushGenerator;
        /// <summary>
        /// Zobrazený obrázek pod labelem vlevo nahoře, vodoznak / logo, nerušivé
        /// </summary>
        public Image ImageWatermark { get; set; }
        /// <summary>
        /// Obsahuje klon sebe sama.
        /// </summary>
        public DialogBackground Clone { get { return (DialogBackground)this.MemberwiseClone(); } }
        #endregion
    }
    #endregion
    #region DialogLabelInfo : Vlastnosti labelu = informační pole
    /// <summary>
    /// DialogLabelInfo : Vlastnosti labelu = informační pole
    /// </summary>
    public class DialogLabelInfo
    {
        public DialogLabelInfo()
        {
            this.Alignment = ContentAlignment.TopLeft;
            this.TextColor = Color.Yellow;
        }
        /// <summary>
        /// Vlastník objektu = stránka
        /// </summary>
        public DialogPageInfo Owner { get; set; }
        public string Text { get; set; }
        /// <summary>
        /// Písmo zprávy. Pokud bude null, použije se globální písmo dialogu (
        /// </summary>
        public Font TextFont { get; set; }
        /// <summary>
        ///  - zdejší nebo společné (pokud zdejší this.Background není zadáno)
        /// </summary>
        public Font CurrentTextFont { get { return (this.TextFont != null ? this.TextFont : (this.Owner != null && this.Owner.Owner != null ? this.Owner.Owner.LabelFont : null)); } }
        /// <summary>
        /// Zarovnání textu. Výchozí je TopLeft.
        /// </summary>
        public ContentAlignment Alignment { get; set; }
        public Color TextColor { get; set; }
        public Color? TextColorAlter { get; set; }
        public double? TimeOn { get; set; }
        public double? TimeOff { get; set; }
        public double? TimeColorAlter { get; set; }
        /// <summary>
        /// Obsahuje klon sebe sama.
        /// Hodnotu TextFont neklonuje, ale kopíruje.
        /// </summary>
        public DialogLabelInfo Clone { get { return (DialogLabelInfo)this.MemberwiseClone(); } }
    }
    #endregion
    #region DialogActionInfo : Popis akce, která se má provést (na daném tlačítku, po timeout, atd)
    /// <summary>
    /// DialogActionInfo : Popis akce, která se má provést (na daném tlačítku, po timeout, atd)
    /// </summary>
    public class DialogActionInfo
    {
        #region Konstruktory
        /// <summary>
        /// Prázdná akce = None, odpovídající objekt se nebude zobrazovat (nemá význam nabízet objekt, který nic neudělá).
        /// </summary>
        public static DialogActionInfo Empty { get { return new DialogActionInfo(DialogActionType.None); } }
        public DialogActionInfo(DialogActionType actionType)
        {
            this.ActionType = actionType;
        }
        public DialogActionInfo(DialogActionType actionType, string text, string info)
        {
            this.ActionType = actionType;
            this.ActionText = text;
            this.ActionInfo = info;
        }
        public DialogActionInfo(DialogActionHandler sendTo)
        {
            this.ActionType = DialogActionType.CallHandler;
            this.SendTo = sendTo;
        }
        public DialogActionInfo(DialogActionHandler sendTo, string text, string info)
        {
            this.ActionType = DialogActionType.CallHandler;
            this.SendTo = sendTo;
            this.ActionText = text;
            this.ActionInfo = info;
        }
        public DialogActionInfo(DialogPageInfo newPage)
        {
            this.ActionType = DialogActionType.GoToPage;
            this.NewPage = newPage;
        }
        public DialogActionInfo(DialogPageInfo newPage, string text, string info)
        {
            this.ActionType = DialogActionType.GoToPage;
            this.NewPage = newPage;
            this.ActionText = text;
            this.ActionInfo = info;
        }
        public DialogActionInfo(string newPageKey)
        {
            this.ActionType = DialogActionType.GoToPage;
            this.NewPageKey = newPageKey;
        }
        public DialogActionInfo(string newPageKey, string text, string info)
        {
            this.ActionType = DialogActionType.GoToPage;
            this.NewPageKey = newPageKey;
            this.ActionText = text;
            this.ActionInfo = info;
        }
        #endregion
        #region Property
        /// <summary>
        /// Vlastník objektu = stránka
        /// </summary>
        public DialogPageInfo Owner { get; set; }
        /// <summary>
        /// Handler, který ošetří aktuální volbu a navrhne další postup
        /// </summary>
        public DialogActionHandler SendTo { get; private set; }
        /// <summary>
        /// Přímo daná stránka, na kterou tato akce vede
        /// </summary>
        public DialogPageInfo NewPage { get; private set; }
        /// <summary>
        /// Klíč další stránky
        /// </summary>
        public string NewPageKey { get; private set; }
        /// <summary>
        /// Specifická akce (typicky InputTextAction, nebo ApplicationExit)
        /// </summary>
        public DialogActionType ActionType { get; private set; }
        /// <summary>
        /// Text akce. 
        /// Pokud bude akce použita pro InputText, jde o text (v combo boxu).
        /// </summary>
        public string ActionText { get; private set; }
        /// <summary>
        /// Informace k akci, Tooltip.
        /// </summary>
        public string ActionInfo { get; private set; }
        /// <summary>
        /// Uživatelem zadaný volný text / opsaný text z ActionText.
        /// </summary>
        public string InputText { get; private set; }
        /// <summary>
        /// Obsahuje klon sebe sama.
        /// Nejde o DeepClone, protože objekty (this.NewPage) se neklonují, ale zkopíruje se reference.
        /// </summary>
        public DialogActionInfo Clone { get { return (DialogActionInfo)this.MemberwiseClone(); } }
        #endregion
    }
    #endregion
    #region delegát DialogActionHandler, třída argumentů DialogActionType, enum akcí DialogActionType
    /// <summary>
    /// Předpis pro handlera události "Dialogová stránka volá Houston"
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public delegate void DialogActionHandler(object sender, DialogActionArgs args);
    /// <summary>
    /// Argument do handleru 
    /// </summary>
    public class DialogActionArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="currentPage"></param>
        public DialogActionArgs(DialogActionInfo currentAction)
        {
            this.CurrentAction = currentAction;
        }
        /// <summary>
        /// Informace o stránce, která událost volá
        /// </summary>
        public DialogPageInfo CurrentPage { get { return this.CurrentAction.Owner; } }
        /// <summary>
        /// Informace o akci, která událost volá
        /// </summary>
        public DialogActionInfo CurrentAction { get; private set; }
        /// <summary>
        /// Nová akce, která se má provést
        /// </summary>
        public DialogActionInfo NewAction { get; set; }

    }
    /// <summary>
    /// Typy akcí
    /// </summary>
    public enum DialogActionType
    {
        /// <summary>
        /// Nic.
        /// Pokud bude 
        /// </summary>
        None,
        /// <summary>
        /// Zavolat handler a zařídit se podle jeho odpovědi = akce uvedená v DialogActionArgs.NewAction
        /// </summary>
        CallHandler,
        /// <summary>
        /// Jít na stránku uvedenou v DialogActionInfo.NewPage
        /// </summary>
        GoToPage,
        /// <summary>
        /// Přejde na stránku, ze které jsme přešli na tuto stránku.
        /// Při přechodu na další stránku (akcí GoToPage nebo CallHandler) 
        /// se do této nové stránky ukládá reference na stránku, z níž se odchází.
        /// Tato akce (GoToPrevPage) se na ní vrátí. Funguje to i vícenásobně.
        /// </summary>
        GoToPrevPage,
        /// <summary>
        /// Jako akce objektu, kde je definována, se převezme akce ze vstupního pole (InputText).
        /// Typicky je tato akce navázaná na buttonu Next, kde v podstatě provede to, co uživatel vybral v nabídce ComboBoxu.
        /// </summary>
        InputTextAction,
        /// <summary>
        /// Přejde na stránku EndPage (pokud existuje), nebo skončí aplikaci.
        /// Stránka EndPage typicky obsahuje rozloučení, žádný input ani button (volitelně akci GoPrev),
        /// pouze TimeOut a jeho akci ApplicationExitNoQuerry.
        /// </summary>
        GoToEndPage,
        /// <summary>
        /// Konec aplikace s dotazem
        /// </summary>
        ApplicationExit,
        /// <summary>
        /// Konec aplikace bez dotazu
        /// </summary>
        ApplicationExitNoQuerry
    }
    /// <summary>
    /// Typ stránky z hlediska organizace dialogu
    /// </summary>
    public enum DialogPageType
    {
        /// <summary>
        /// Žádný
        /// </summary>
        None,
        /// <summary>
        /// Běžná stránka dialogu
        /// </summary>
        Standard,
        /// <summary>
        /// Úvodní stránka, je zobrazena jako první po rozsvícení dialogu
        /// Taková může být jen jedna, je to ta, která byla zadána jako poslední s tímto typem.
        /// </summary>
        Main,
        /// <summary>
        /// Poslední stránka dialogu.
        /// Taková může být jen jedna, je to ta, která byla zadána jako poslední s tímto typem.
        /// </summary>
        End
    }
    #endregion
    #region DialogSetSamples : Generátor samplů dialogů (DialogSetInfo) - pro testy
    /// <summary>
    /// DialogSetSamples : Generátor samplů dialogů (DialogSetInfo) - pro testy
    /// </summary>
    public class DialogSetSamples
    {
        public static DialogSetInfo CreateSet1()
        {
            DialogSetInfo set = new DialogSetInfo();

            DialogPageInfo page0 = new DialogPageInfo("0000");
            set.Add(page0);
            page0.Label = new DialogLabelInfo() { Text = "Vítejte v systému. Co pro vás mohu udělat?", TextColor = Color.LightYellow, TimeOn = 0.75d, TimeOff = 2.2d };
            page0.ButtonPrevAction = DialogActionInfo.Empty;
            page0.ButtonNextAction = new DialogActionInfo("0001");

            DialogPageInfo page1 = new DialogPageInfo("0001");
            set.Add(page1);
            page1.Label = new DialogLabelInfo() { Text = "Kdo jste prosím?", TextColor = Color.LightBlue, TimeOn = 0.75d, TimeOff = 2.2d };
            page1.ButtonPrevAction = new DialogActionInfo("0000");
            page1.ButtonNextAction = new DialogActionInfo("0002");

            DialogPageInfo page2 = new DialogPageInfo("0002");
            set.Add(page2);
            page2.Label = new DialogLabelInfo() { Text = "Vás neznám.", TextColor = Color.LightGreen, TimeOn = 0.75d, TimeOff = 2.2d };
            page2.ButtonPrevAction = new DialogActionInfo("0001");
            page2.ButtonNextAction = DialogActionInfo.Empty;

            DialogPageInfo pageEnd = new DialogPageInfo(DialogPageType.End);
            set.Add(pageEnd);
            pageEnd.Label = new DialogLabelInfo() { Text = "Bylo mi potěšením.", TextColor = Color.LightGray, TimeOn = 0.75d, TimeOff = 2.2d };
            pageEnd.TimeOut = 7d;
            pageEnd.TimeOutAction = new DialogActionInfo(DialogActionType.ApplicationExitNoQuerry);

            return set;
        }
    }
    #endregion
}
